package com.yf.customdubbo;

import com.yf.customdubbo.registry.IServiceDiscovery;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.Proxy;

public class RpcClientProxy {
    private IServiceDiscovery serviceDiscovery;

    public RpcClientProxy(IServiceDiscovery serviceDiscovery){
        this.serviceDiscovery=serviceDiscovery;
    }


    public <T> T create(final Class<T> interfaceClass){
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class<?>[]{interfaceClass},
                ((proxy, method, args) ->{
                    //封装RpcRequest对象
                    RpcRequest request=new RpcRequest();
                    request.setClassName(method.getDeclaringClass().getName());
                    request.setMethondName(method.getName());
                    request.setTypes(method.getParameterTypes());
                    request.setParams(args);

                    //服务发现
                    String serviceName=interfaceClass.getName();
                    String serviceAddress=serviceDiscovery.discovery(serviceName);

                    //解析host和ip
                    String[] arrs=serviceAddress.split(":");
                    String host=arrs[0];

                    int port=Integer.parseInt(arrs[1]);

                    final RpcProxyHandler rpcProxyHandler=new RpcProxyHandler();



                    /*
                     * NioEventLoopGroup实际上就是个线程池,
                     * NioEventLoopGroup在后台启动了n个NioEventLoop来处理Channel事件,
                     * 每一个NioEventLoop负责处理m个Channel,
                     * NioEventLoopGroup从NioEventLoop数组里挨个取出NioEventLoop来处理Channel
                     */

                    //通过netty的方式进行连接和发送
                    EventLoopGroup group=new NioEventLoopGroup();
                    try{
                        Bootstrap b=new Bootstrap();
                        b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true)
                                .handler(

                                        new ChannelInitializer<SocketChannel>() {

                                            @Override
                                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                                ChannelPipeline pipeline=socketChannel.pipeline();
                                                pipeline.addLast("frameDecoder",new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                                                pipeline.addLast("frameEncoder",new LengthFieldPrepender(4));
                                                pipeline.addLast("encoder",new ObjectEncoder());
                                                pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                                                pipeline.addLast("handler",rpcProxyHandler);
                                            }
                                        }

                                );

                        //连接服务地址
                        ChannelFuture future=b.connect(host,port).sync();
                        //将封装好的request对象写过去
                        future.channel().writeAndFlush(request);

                        future.channel().closeFuture().sync();
                    }catch (Exception e){

                    }finally {
                        group.shutdownGracefully();
                    }

                    return rpcProxyHandler.getResponse();
                } ));
    }




}
